/**
 * Copyright (c) 2018, Alex. All rights reserved.
 */
package com.oschina.bottle.poi.imp;

import com.oschina.bottle.poi.FileInfo;
import com.oschina.bottle.poi.Head;
import com.oschina.bottle.poi.Importer;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.any23.encoding.TikaEncodingDetector;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

/**
 * csv文件导入
 *
 * @author <a href="mailto:zhongchao@gegejia.com">zhong</a>
 * @version 1.0 2018/2/5
 * @since 1.0
 */
public class CsvImporter implements Importer {

    @Override
    public void resolve(FileInfo fileInfo) throws IOException {
        InputStreamReader fr = null;
        BufferedReader br = null;
        try {
            BufferedInputStream bis = new BufferedInputStream(fileInfo.getInput());
            String charset = guessCharset(bis);
            fr = new InputStreamReader(bis, charset);
            br = new BufferedReader(fr);
            //先读取流，如果失败，不再创建集合
            List<Map<String, Object>> dataList = new ArrayList<>();
            String rec = null;
            for (int line = 0; (rec = br.readLine()) != null; line++) {
                if (line == fileInfo.getHeaderIndex()) {
                    //                    resolveHeader(fileInfo, rec,converter);
                    continue;
                }
                if (CollectionUtils.isEmpty(fileInfo.getHeads())) {
                    //头部信息还未读取
                    continue;
                }
                Map<String, Object> data = resolveContent(rec, fileInfo.getHeads());
                if (data != null) {
                    dataList.add(data);
                }
            }
            fileInfo.setData(dataList);
        } finally {
            //流关闭操作，但不包括fileInfo中的流关闭操作
            if (fr != null) {
                fr.close();
            }
            if (br != null) {
                br.close();
            }
        }
    }

    /**
     * 单行文件内容解析
     *
     * @param rec 单行文本
     * @param heads 头信息
     * @return key:fieldCode|value为取值
     * @throws RuntimeException 文件格式异常
     */
    private Map<String, Object> resolveContent(String rec, List<Head> heads) throws RuntimeException {
        Map<String, Object> data = new HashMap<>();
        String[] lines = splitLine(rec);
        boolean isEmpty = true;
        for (int i = 0; i < lines.length; i++) {
            String value = lines[i];
            if(StringUtils.isNotBlank(value)) {
                isEmpty = false;
            }
            Head head = heads.get(i);
            String fieldCode = head.getFieldName();
            data.put(fieldCode, head.convertType(value));
        }
        if(isEmpty) {
            return null;
        }

        return data;
    }

    /**
     * 单行解析
     *
     * @param src 字符串
     * @return 解析每个column的值组成的数组
     * @throws RuntimeException 文件格式错误
     */
    private static String[] splitLine(String src) throws RuntimeException {
        if (StringUtils.isBlank(src)) {
            return new String[0];
        }
        StringBuilder sb = new StringBuilder();
        Vector<String> result = new Vector<>();
        boolean beginWithQuote = false;
        for (int i = 0; i < src.length(); i++) {
            char ch = src.charAt(i);
            if (ch == '\"') {
                if (beginWithQuote) {
                    i++;
                    if (i >= src.length()) {
                        result.addElement(sb.toString());
                        sb = new StringBuilder();
                        beginWithQuote = false;
                    } else {
                        ch = src.charAt(i);
                        if (ch == '\"') {
                            sb.append(ch);
                        } else if (ch == ',') {
                            result.addElement(sb.toString());
                            sb = new StringBuilder();
                            beginWithQuote = false;
                        } else {
                            throw new RuntimeException("CVS文件错误的使用了双引号");
                        }
                    }
                } else if (sb.length() == 0) {
                    beginWithQuote = true;
                } else {
                    throw new RuntimeException("CVS文件错误的使用了双引号");
                }
            } else if (ch == ',') {
                if (beginWithQuote) {
                    sb.append(ch);
                } else {
                    result.addElement(sb.toString());
                    sb = new StringBuilder();
                    beginWithQuote = false;
                }
            } else {
                sb.append(ch);
            }
        }
        if (sb.length() != 0) {
            if (beginWithQuote) {
                throw new RuntimeException("CVS文件错误的使用了双引号");
            } else {
                result.addElement(sb.toString());
            }
        }
        String rs[] = new String[result.size()];
        for (int i = 0; i < rs.length; i++) {
            rs[i] = result.elementAt(i);
        }
        return rs;
    }

    public static String guessCharset(InputStream is) throws IOException {
        return new TikaEncodingDetector().guessEncoding(is);
    }
}
